#include "global_vars.h"
void compute_performance(int sd, short event, void* arg) {

	gettimeofday(&performance_end_time, NULL);
	gettimeofday(&end_time, NULL);

	interval_performance->interval_time = measure_time_difference(performance_end_time, performance_start_time);
	interval_performance->total_time = measure_time_difference(end_time, start_time);

	interval_performance->interval_sending_throughput = calculate_throughput((interval_performance->interval_bytes_sent), interval_performance->interval_time);
	interval_performance->interval_recv_throughput = calculate_throughput(interval_performance->interval_bytes_recv, interval_performance->interval_time);
	interval_performance->interval_delivery_throughput = calculate_throughput(interval_performance->interval_num_packets_delivered * (sizeof(msg) - MSG_HEADER_SIZE), interval_performance->interval_time);
	interval_performance->interval_proposing_throughput = calculate_throughput(interval_performance->interval_bytes_proposed, interval_performance->interval_time);
	printf(" all: %f\n", interval_performance->interval_latency);
	if (interval_performance->num_packets_delivered_latency == 0)
		interval_performance->num_packets_delivered_latency = 0;
	else
		interval_performance->interval_latency = interval_performance->interval_latency / (double) (interval_performance->num_packets_delivered_latency);

	store_performance_in_array(&performances[0], &performance_index, interval_performance);
	print_performance(interval_performance);
	nulify_performance(interval_performance);

	if (performance_index >= STOPPING_CONDITION) {
		store_performance_in_file(performance_file, latency_file, sd_avg_file, performance_index);
		rbdestroy(myTree);
		exit(1);
	}
	gettimeofday(&performance_start_time, NULL);
	int status = evtimer_add(timeout2, &tv2);
	assert(status >= 0);
}
void nulify_performance(performance * p) {
	p->interval_time = 0;
	p->interval_proposing_throughput = 0;
	p->interval_sending_throughput = 0;
	p->interval_delivery_throughput = 0;
	p->interval_recv_throughput = 0;
	p->interval_latency = 0;
	p->interval_bytes_sent = 0;
	p->interval_bytes_recv = 0;
	p->interval_bytes_proposed = 0;
	p->interval_num_packets_delivered = 0;
	p->num_packets_delivered_latency = 0;
	p->interval_num_packets_propsoed = 0;
	p->diff = 0;
	p->num_interrupts = 0;

	if (performance_index == 0) {
		p->total_time = 0;
		p->latency_counter = 0;
	}
}
void store_performance_in_array(performance * performances_array, int * performance_index, performance *i_p) {
	memcpy((performances_array + *performance_index), i_p, sizeof(performance));
	*(performance_index) = *(performance_index) + 1;
}
void print_performance(performance * p) {
	printf("INTERVAL TIME: %f		TOTAL_TIME: %f\n", p->interval_time, p->total_time);
	printf("SEND THR %f		BYTES: %f\n", p->interval_sending_throughput, p->interval_bytes_sent);
	printf("RECV THR %f		BYTES: %f\n", p->interval_recv_throughput, p->interval_bytes_recv);
	printf("PROP THR %f		BYTES: %f\n", p->interval_proposing_throughput, p->interval_bytes_proposed);
	printf("DELI THR %f		NUM:   %d\n", p->interval_delivery_throughput, p->interval_num_packets_delivered);
	printf("LATENCY: %f		NUM:   %d	prop: %d\n", p->interval_latency, p->num_packets_delivered_latency, p->interval_num_packets_propsoed);
	printf("SELF: %d PRE: %d  PRE PRE: %d\n", get_config_info()->self_id, get_predecessot(get_config_info()->self_id), get_pre_predecessor(get_config_info()->self_id));
	printf("DIFF: %f	INTERUUPTS: %d\n", p->diff, p->num_interrupts);
	printf("---------------------------------------------------------------------\n");
}
double measure_time_difference(struct timeval now, struct timeval past) {
	struct timeval elapsed_interval;

	elapsed_interval.tv_sec = now.tv_sec - past.tv_sec;
	elapsed_interval.tv_usec = (now.tv_usec > past.tv_usec ? now.tv_usec - past.tv_usec : past.tv_usec - now.tv_usec);
	double msec_interval = 1000 * elapsed_interval.tv_sec + elapsed_interval.tv_usec / (double) 1000;

	return msec_interval;
}
double calculate_throughput(int bytes, double elapsed_time) {
	double thr = (bytes / (double) (1024 * 1024));
	thr = thr / (double) elapsed_time;
	thr = thr * 1000 * 8;
	return thr;
}
void store_performance_in_file(const char * performance_file, const char * latency_file, const char * sd_avg_file, int num_entries) {

	FILE *fp;
	int i;

	fp = fopen(performance_file, "w");
	assert(fp != NULL);

	for (i = DISCARD; i < num_entries - DISCARD; i++) {

		fprintf(fp, "%d %d %d %d %f %f %f %f %f %f %f %f %d %f\n", i + 1, //1
				submit_per_wake, //2
				submit_per_wake, //3
				(int) tv1.tv_usec, //4
				performances[i].interval_time, //5
				performances[i].interval_delivery_throughput, //6
				performances[i].interval_sending_throughput, //7
				performances[i].interval_recv_throughput, //8
				performances[i].interval_proposing_throughput, //9
				performances[i].interval_bytes_sent, //10
				performances[i].interval_bytes_recv, //11
				performances[i].interval_bytes_proposed, //12
				performances[i].interval_num_packets_delivered, //13
				performances[i].interval_latency); //14
	}

	fclose(fp);

	fp = fopen(latency_file, "w");
	assert(fp != NULL);

	for (i = 0; i < interval_performance->latency_counter; i++)
		fprintf(fp, "%f\n", latency[i]);

	fclose(fp);

}

